// ThreadHistory.cpp: implementation of the CThreadHistory class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Rock.h"
#include "ThreadHistory.h"


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CThreadHistory::CThreadHistory()
{
	m_Created = FALSE;
	m_hEdit = NULL;

	memset(&m_cfTitle, 0, sizeof(m_cfTitle));
	m_cfTitle.cbSize = sizeof(CHARFORMAT);
	m_cfTitle.dwMask = CFM_BOLD | CFM_COLOR | CFM_FACE | CFM_ITALIC | CFM_SIZE | CFM_STRIKEOUT | CFM_UNDERLINE;
	m_cfTitle.crTextColor = RGB(128, 128, 128);
	_tcscpy(m_cfTitle.szFaceName, _T("MS Sans Serif"));
	m_cfTitle.bPitchAndFamily = FF_SWISS;
	m_cfTitle.yHeight = 240;

	memset(&m_cfText, 0, sizeof(m_cfText));
	m_cfText.cbSize = sizeof(CHARFORMAT);
	m_cfText.dwMask = CFM_BOLD | CFM_COLOR | CFM_FACE | CFM_ITALIC | CFM_SIZE | CFM_STRIKEOUT | CFM_UNDERLINE;
	m_cfText.crTextColor = RGB(0, 0, 0);
	_tcscpy(m_cfText.szFaceName, _T("MS Sans Serif"));
	m_cfText.bPitchAndFamily = FF_SWISS;
	m_cfText.yHeight = 240;
}

CThreadHistory::~CThreadHistory()
{

}
	
void CThreadHistory::AppendText(const char* WhoSay,const char* Text){
	int nFirstLine = (int)::SendMessage( m_hEdit, EM_GETFIRSTVISIBLELINE, 0, 0 );
		
	int	 len = GetWindowTextLength(m_hEdit);

	CHARRANGE cr;
	//	Hide any selection and select the end of text marker.
	::SendMessage(m_hEdit,EM_HIDESELECTION, TRUE,TRUE);
	cr.cpMax = len;
	cr.cpMin = len;
	::SendMessage(m_hEdit,EM_EXSETSEL, 0, (LPARAM)&cr);

	::SendMessage(m_hEdit,EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&m_cfTitle);
	::SendMessage(m_hEdit,EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)WhoSay); 	

	len = GetWindowTextLength(m_hEdit);
	cr.cpMax = len;
	cr.cpMin = len;
	::SendMessage(m_hEdit,EM_EXSETSEL, 0, (LPARAM)&cr);

	::SendMessage(m_hEdit,EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&m_cfText);
	::SendMessage(m_hEdit,EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)Text); 
    ::SendMessage(m_hEdit,EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)"\r\n"); 

	len = GetWindowTextLength(m_hEdit);
	cr.cpMax = len;
	cr.cpMin = len;
	::SendMessage(m_hEdit,EM_EXSETSEL, 0, (LPARAM)&cr);

	if (len > 125000)
	{
		cr.cpMax = 0;
		cr.cpMin = 50000;
		::SendMessage(m_hEdit,EM_EXSETSEL, 0, (LPARAM)&cr);

		string s;
		::SendMessage(m_hEdit,EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)s.c_str());
		
		cr.cpMax = len;
		cr.cpMin = len;
		::SendMessage(m_hEdit,EM_EXSETSEL, 0, (LPARAM)&cr);
	}
    

	::SendMessage(m_hEdit,EM_HIDESELECTION, FALSE,TRUE);

	int	nFirstLineNow = (int)::SendMessage( m_hEdit, EM_GETFIRSTVISIBLELINE, 0, 0 );
	::SendMessage( m_hEdit, EM_LINESCROLL, 0, (LPARAM) nFirstLine - nFirstLineNow);
//	::SendMessage(m_hEdit,EM_SCROLLCARET, 0, 0);
}
	
void CThreadHistory::AppendFromStrem(const char* text){

	int nFirstLine = (int)::SendMessage( m_hEdit, EM_GETFIRSTVISIBLELINE, 0, 0 );

	CHARRANGE cr;	
	int	 len = GetWindowTextLength(m_hEdit);
	cr.cpMax = len;
	cr.cpMin = len;
	::SendMessage(m_hEdit,EM_EXSETSEL, 0, (LPARAM)&cr);

 	EDITSTREAM es;
	string Text = text;
	es.dwCookie = (DWORD)&Text;
	es.pfnCallback = StreamInCallback;
	::SendMessage(m_hEdit, EM_STREAMIN, SF_RTF|SFF_SELECTION, (LPARAM)&es);
		
	len = GetWindowTextLength(m_hEdit);
	cr.cpMax = len;
	cr.cpMin = len;
	::SendMessage(m_hEdit,EM_EXSETSEL, 0, (LPARAM)&cr);

	if (len > 125000)
	{
		cr.cpMax = 0;
		cr.cpMin = 50000;
		::SendMessage(m_hEdit,EM_EXSETSEL, 0, (LPARAM)&cr);

		string s;
		::SendMessage(m_hEdit,EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)s.c_str());
		
		cr.cpMax = len;
		cr.cpMin = len;
		::SendMessage(m_hEdit,EM_EXSETSEL, 0, (LPARAM)&cr);
	}
    

	::SendMessage(m_hEdit,EM_HIDESELECTION, FALSE,TRUE);

	int	nFirstLineNow = (int)::SendMessage( m_hEdit, EM_GETFIRSTVISIBLELINE, 0, 0 );
	::SendMessage( m_hEdit, EM_LINESCROLL, 0, (LPARAM) nFirstLine - nFirstLineNow);
}

void CThreadHistory::ClearText(){
	::SetWindowText(m_hEdit,"");
}

void CThreadHistory::SaveTempMemory(){

	EDITSTREAM es;
	es.dwCookie = (DWORD)&m_TempMemory;
	es.pfnCallback = StreamOutCallback;
	::SendMessage(m_hEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es); 
}

void CThreadHistory::LoadTmepMemory(){
 	EDITSTREAM es;
	es.dwCookie = (DWORD)&m_TempMemory;
	es.pfnCallback = StreamInCallback;
	::SendMessage(m_hEdit, EM_STREAMIN, SF_RTF, (LPARAM)&es); 
}
	
void CThreadHistory::SaveAsRTFFile(FILE* file){
	EDITSTREAM es;
	es.dwCookie = (DWORD) file;
	es.pfnCallback = SaveFileCallback;
	::SendMessage(m_hEdit, EM_STREAMOUT, SF_RTF, (LPARAM)&es); 
	fflush(file);
	fclose(file);
}

DWORD CALLBACK CThreadHistory::SaveFileCallback(DWORD dwCookie, 
												LPBYTE pbBuff, LONG cb, LONG *pcb){
	*pcb = fwrite(pbBuff,1,cb,(FILE*)dwCookie);
	return 0;
}

DWORD CALLBACK CThreadHistory::StreamInCallback(DWORD dwCookie, 
												LPBYTE pbBuff, LONG cb, LONG *pcb)
{
   
    string*  Text = (string*)(dwCookie);
	int n = min(cb,Text->size());
	strncpy((LPSTR) pbBuff, Text->c_str() , n );
    Text->erase(0,n); 
	*pcb = n;

	return 0;
}

DWORD CALLBACK CThreadHistory::StreamOutCallback(DWORD dwCookie, 
												 LPBYTE pbBuff, LONG cb, LONG *pcb)
{
	char*	buf;
	buf = new char[ cb + 1 ];
	buf[ cb ] = (char) 0;
	strncpy(buf, (LPCSTR) pbBuff, cb);

	string*  Text = (string *)(dwCookie);
	
	*Text += buf;
	*pcb = strlen(buf);
	delete[] buf;
	return 0;
}

void CThreadHistory::Layout(bool Redraw /*= true*/){
	CThreadTitleView::Layout(Redraw);
	if(m_Created){
		::MoveWindow(m_hEdit,m_rcClient.left,m_rcClient.top,RectWidth(m_rcClient),RectHeight(m_rcClient),TRUE);
	}
};
LRESULT CThreadHistory::OnCreate( WPARAM wParam, LPARAM lParam) 
{		
	
	// Create the edit control
	DWORD style = WS_VISIBLE | WS_CHILD |ES_LEFT |ES_READONLY|//WS_BORDER|ES_AUTOHSCROLL|ES_AUTOVSCROLL|
		ES_MULTILINE|ES_WANTRETURN|WS_HSCROLL|WS_VSCROLL;
	
	m_hEdit =  CreateWindowEx(
		WS_EX_STATICEDGE,      // extended window style
		RICHEDIT_CLASS,  // pointer to registered class name
		NULL, // pointer to window name
		style,        // window style
		0,                // horizontal position of window
		0,                // vertical position of window
		0,           // window width
		0,          // window height
		m_hWnd,      // handle to parent or owner window
		(HMENU)100,          // handle to menu, or child-window identifier
		GetHinstance(),  // handle to application instance
		NULL       // pointer to window-creation data
		);
	assert(m_hEdit != NULL);
	if(m_hEdit==NULL)return -1;	
	LoadTmepMemory();
	m_Created = true;
	//Layout();
    return 0;
}

LRESULT CThreadHistory::Reaction(UINT message, WPARAM wParam, LPARAM lParam){
	switch(message){
	case WM_SIZE:
		return OnSize(wParam,lParam);
	case WM_CREATE:
		return OnCreate(wParam,lParam);
	case WM_DESTROY:
		SaveTempMemory();
	default:
		return CThreadTitleView::Reaction(message,wParam,lParam);
	}
}

LRESULT CThreadHistory::OnSize(WPARAM wParam, LPARAM lParam){
    Layout(true);
	return 0;
}

